<template>
  <div class="container">
    <div class="timeLine">
      <div class="player">
        <img src="../assets//stop.png" alt="" title="点击暂停" v-show="player" @click="stop" height="40px">
        <img src="../assets//continue.png" alt="" title="点击播放" v-show="!player" @click="play" style="height:40px">
      </div>
      <div class="timeLineNode" v-for="(item, index) in timeLineContent" :key="index">
        <div :class="['dot',index == curHour?'activeDot':'']" @click="selectTime(index)"></div>
        <div :class="['text',index == curHour?'activeText':'']" @click="selectTime(index)">{{ item.content }}</div>
      </div>
    </div>
    <div class="box" id="box">
    </div>
  </div>
  <div class="floating">
    <img src="../assets/toLeft.png" alt="" style="width:20px">
    <div>
      <div @click="startOptimize" class="button">开始仿真</div>
      <div @click="showUnunit" class="button">显示未连接用户</div>
      <div class="button">
        基站休眠方案
        <el-select v-model="sleepType" placeholder="请选择基站休眠方案" style="width: 100px">
          <el-option
            v-for="item in options"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </div>
    </div>
  </div>
</template>
<script setup lang="js">
import {jsPlumb} from 'jsplumb'
import { onBeforeMount,onBeforeUnmount,reactive, ref ,onMounted, watch} from 'vue';
import { getOptimizedResult ,getUserInfo ,getStationInfo } from '@/service/api';
import useResult from '@/service/result';
import { ElLoading ,ElMessage } from 'element-plus'
import userSVGString from '../assets/phone.svg'
const resultStore = useResult()
//颜色选择器
const colorSelectOptions = [
  '#F4DC96','#CCF496','#95F6E9','#86ABF5','#D886F5','#F586B6','#14AF18','#5219E2'
]
//基站休眠方案选择
const sleepType = ref('result_optimal')
const options = [
  {
    value: 'result_optimal',
    label: '用户关联+基站休眠',
  },
  {
    value: 'result_unsleep',
    label: '仅用户关联',
  },
  {
    value: 'result_without_association',
    label: '仅基站休眠',
  },
]
const timeLineContent = reactive([]);
//位置取值范围
const range = 1000;
let unitHeight
let unitWidth
//基站
const stations = reactive([])
//用户
const users = reactive([])
//计时器
let Timer
//播放与暂停控制
const player = ref(false)
//当前展示的时间
let curHour = ref(0)
//当前选中的用户节点
const curNode = ref()
const myJsPlumb = jsPlumb.getInstance()
//恢复透明度
const refreshOpacity = () =>{
  users.forEach((user)=>{
    user.node.style.opacity = '100%'
  })
  stations.forEach((station)=>{
    station.node.style.opacity = '100%'
  })
}
//生成结点
const initNode = () =>{
  const node = document.createElement('div')
  node.style.display='inline-block'
  // node.style.backgroundColor='black'
  node.style.borderRadius='50%'
  node.style.position='absolute'
  node.style.cursor='pointer'
  // node.style.transform='translate(-50%,-50%)'
  return node
}
//生成基站
const initStation = async (originNode) =>{
  const childNode = document.createElement('div')
  Object.assign(childNode.style, {
    width: '140px',
    // height: '20px',
    padding:'10px',
    border: '1px solid rgba(0,0,0,0.4)',
    borderRadius: '12px', /* 圆角半径 */
    boxShadow:' 0 4px 8px rgba(0, 0, 0, 1)', /* 添加阴影 */
    backgroundColor:'white',
    zIndex:50,
    position:'absolute',
    display:'none'
  });
  box.appendChild(childNode);
  // 创建一个新的图片节点
  const image = new Image();
  originNode.style.height='80px'
  originNode.style.width='80px'

  //获取基站位置信息
  getStationInfo().then((res)=>{
    for(let i=0;i<res.data.number;i++){
      stations.push(res.data.position[i])
      const X = stations[i].X*unitWidth
      const Y = stations[i].Y*unitHeight
      stations[i].node = originNode.cloneNode()
      //真实基站特殊标注
      if(i==0){
        stations[i].node.style.height = '120px'
        stations[i].node.style.width = '120px'
        //定位偏移 这里注意要偏移自身大小的一半
        stations[i].node.style.left=`${X-60}px`
        stations[i].node.style.top=`${Y-60}px`
        image.src = "/src/assets/baseStation3.png";
        image.style.width = "120px"; // 设置图片的宽度
        image.style.height = "120px"; // 设置图片的高度
        stations[i].node.appendChild(image.cloneNode());
      }else{
        //定位偏移 这里注意要偏移自身大小的一半
        stations[i].node.style.left=`${X-40}px`
        stations[i].node.style.top=`${Y-40}px`
        image.src = "/src/assets/baseStation4.png"; // 替换为你的图片路径
        image.style.width = "80px"; // 设置图片的宽度
        image.style.height = "80px"; // 设置图片的高度
        stations[i].node.appendChild(image.cloneNode());
      }
      box.appendChild(stations[i].node)
      stations[i].node.addEventListener('click',()=>{
        if(curNode.value){
          myJsPlumb.deleteEveryConnection();
          refreshOpacity()
        }
        curNode.value = drawLines(i,true)
      })
      //鼠标放在节点上，显示信息
      stations[i].node.addEventListener('mouseenter',()=>{
        // 显示 childNode 并定位
        childNode.innerHTML = `<div>类型：基站</div/><div>序号：${i}</div/><div>坐标：(${stations[i].X},${stations[i].Y})</div/><div>碳排放:(${stations[i].CO2})</div><div>功耗：${stations[i].consumption}</div>`
        childNode.style.display = 'block';
        childNode.style.left = `${X-70>0?X-70:0}px`;//减去自身宽度的一半，移位到中间
        childNode.style.top = `${Y + (i==0?60:40)}px`; // 偏移一些距离，避免遮挡节点
      })
      //鼠标移开时去掉详细信息
      stations[i].node.addEventListener('mouseleave',()=>{
        childNode.style.display = 'none';
      })
    }
  })
}
//生成用户
const initUsers = async(originNode) =>{
  //用户节点的子元素，展示详细信息
  const childNode = document.createElement('div')
  Object.assign(childNode.style, {
    width: '140px',
    // height: '20px',
    padding:'10px',
    border: '1px solid rgba(0,0,0,0.4)',
    borderRadius: '12px', /* 圆角半径 */
    boxShadow:' 0 4px 8px rgba(0, 0, 0, 1)', /* 添加阴影 */
    backgroundColor:'white',
    zIndex:50,
    position:'absolute',
    display:'none'
  });
  box.appendChild(childNode);
  //微调节点样式
  originNode.style.width = '40px'
  originNode.style.height = '40px'
  originNode.style.animation = 'emphasizeAnimation 1s infinite alternate'
  //获取用户位置等信息
  getUserInfo({time:curHour.value}).then((res)=>{
    for(let i=0;i<res.data.number;i++){
    users.push(res.data.data[i])
    //计算在屏幕中的位置
    const X = users[i].position.X * unitWidth
    const Y = users[i].position.Y * unitHeight
    console.log(X,Y)
    users[i].node = originNode.cloneNode()
    //定位偏移 这里注意要偏移自身大小的一半
    users[i].node.style.left=`${X-20}px`
    users[i].node.style.top=`${Y-20}px`
    users[i].node.style.zIndex=0
    //挂载用户节点
    box.appendChild(users[i].node)
    //加图片
    users[i].node.innerHTML = '<svg t="1743163587110" style="width:40px;height:40px" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13965" width="200" height="200"><path d="M820.409449 797.228346q0 25.19685-10.07874 46.866142t-27.716535 38.299213-41.322835 26.204724-50.897638 9.574803l-357.795276 0q-27.212598 0-50.897638-9.574803t-41.322835-26.204724-27.716535-38.299213-10.07874-46.866142l0-675.275591q0-25.19685 10.07874-47.370079t27.716535-38.80315 41.322835-26.204724 50.897638-9.574803l357.795276 0q27.212598 0 50.897638 9.574803t41.322835 26.204724 27.716535 38.80315 10.07874 47.370079l0 675.275591zM738.771654 170.330709l-455.559055 0 0 577.511811 455.559055 0 0-577.511811zM510.992126 776.062992q-21.165354 0-36.787402 15.11811t-15.622047 37.291339q0 21.165354 15.622047 36.787402t36.787402 15.622047q22.173228 0 37.291339-15.622047t15.11811-36.787402q0-22.173228-15.11811-37.291339t-37.291339-15.11811zM591.622047 84.661417q0-8.062992-5.03937-12.598425t-11.086614-4.535433l-128 0q-5.03937 0-10.582677 4.535433t-5.543307 12.598425 5.03937 12.598425 11.086614 4.535433l128 0q6.047244 0 11.086614-4.535433t5.03937-12.598425z" p-id="13966"></path></svg>'
    // users[i].node.appendChild(image.cloneNode());
    //鼠标放在节点上，显示信息
    users[i].node.addEventListener('mouseenter',()=>{
      // 显示 childNode 并定位
      childNode.innerHTML = `<div>类型：用户</div/><div>序号：${i}</div/><div>坐标：(${users[i].position.X},${users[i].position.Y})</div/><div>信噪比要求：${users[i].user_snr}</div/><div>信道状态：${users[i].status}</div/>`
      childNode.style.display = 'block';
      childNode.style.left = `${X-70>0?X-70:0}px`;//减去自身宽度的一半，移位到中间
      childNode.style.top = `${Y + 20}px`; // 偏移一些距离，避免遮挡节点
    })
    //鼠标移开时去掉详细信息
    users[i].node.addEventListener('mouseleave',()=>{
      childNode.style.display = 'none';
    })
    //增加点击事件
    users[i].node.addEventListener('click',()=>{
      if(curNode.value){
        myJsPlumb.deleteConnectionsForElement(curNode.value);
      }
      curNode.value = drawLines(i,false)
    })
  }
  })
}
//目标用户与基站连线
const drawLines = (index,isStation) =>{
  console.log(index,isStation)
  let connection
  myJsPlumb.ready(()=> {
    //点击基站，连接用户
    if(isStation){
      console.log('点击基站，连接用户')
      for(let i=0;i<users.length;i++){
        console.log(users[i],users[i].res_x_ue,index)
        if(users[i].res_x_ue===index){
          console.log('连接用户序号:',i)
          connection = myJsPlumb.connect({
          source: users[i].node,
          target: stations[index].node,
          anchor: 'Continuous',
          connector: ['Straight'],
          endpoint: 'Blank',
          overlays: [  
            // ["Label", {
            //   label: `用户${isStation?i:index} 基站${isStation?index:i} 信道状态${channel_status[isStation?i:index][isStation?index:i]}`,
            //   cssClass: "label-class",
            //   labelStyle: { color: "red", fontSize: "14px" },
            //   location: 0.5 // 标签位置，0 表示起点，1 表示终点，0.5 表示中间
            // }],
            ["Arrow",{ width: 8, length: 8, location: 1}]
          ],
          // 添加样式
          paintStyle: { stroke: colorSelectOptions[index], strokeWidth: 2 }, // connector
          // endpointStyle: { fill: '#909399', outlineStroke: '#606266', outlineWidth: 1 } // endpoint
        })
        }
      }
    }else{
      console.log('点击用户，连接基站')
      connection = myJsPlumb.connect({
        source: users[index].node,
        target: stations[users[index].res_x_ue].node,
        anchor: 'Continuous',
        // anchor: [0.5, 0.5],
        connector: ['Straight'],
        endpoint: 'Blank',
        overlays: [  
          // ["Label", {
          //   label: `用户${isStation?i:index} 基站${isStation?index:i} 信道状态${channel_status[isStation?i:index][isStation?index:i]}`,
          //   cssClass: "label-class",
          //   labelStyle: { color: "red", fontSize: "14px" },
          //   location: 0.5 // 标签位置，0 表示起点，1 表示终点，0.5 表示中间
          // }],
          ["Arrow",{ width: 8, length: 8, location: 1 }]
        ],
        // 添加样式
        paintStyle: { stroke: colorSelectOptions[users[index].res_x_ue], strokeWidth: 2 }, // connector
        // endpointStyle: { fill: '#909399', outlineStroke: '#606266', outlineWidth: 1 } // endpoint
      })
    }
    if(isStation){
      stations.forEach((station,i) => {
        if(i !== index){
          station.node.style.opacity = '30%'
        }
      });
    }else{
      users.forEach((user,i) => {
        if(i !== index){
          user.node.style.opacity = '30%'
        }
      });
    }
  })
  return connection?.sourceId
}
//展示未连接的用户
const showUnunit = () =>{
  for(let i=0;i<users.length;i++){
    if(users[i].station>3){
      users[i].node.style.transition='transform 0.5s ease'
      users[i].node.style.transform='scale(2)'
      setTimeout(()=>{
        users[i].node.style.transform='scale(1)'
      },500)
    }
  }
}
//播放与暂停
const stop = () =>{
  clearInterval(Timer)
  player.value = false
}
const play = () =>{
  //立即刷新一次
  ElMessage('开始自动播放')
  setTimeout(()=>{
    curHour.value = (curHour.value + 1) % 24
    selectTime(curHour,true)
    //开启定时器
    Timer = setInterval(()=>{
      console.log('interVal')
      curHour.value = (curHour.value + 1) % 24
      selectTime(curHour,true)
    },2000)
  },500)
  player.value = true
}
//加载动画
const startLoadScreen = () => {
  return ElLoading.service({
    lock: true,
    text: '加载中',
    background: 'rgba(0, 0, 0, 0.7)',
  })
}
//开始运行
const startOptimize = () =>{
  console.log(`获取时刻${curHour.value},算法${sleepType.value}的数据`)
  //有数据就加载数据
  if(resultStore.check(curHour.value)){
    //播放加载动画
    const loading = startLoadScreen()
    setTimeout(()=>{
      const curData = resultStore.data[curHour.value][sleepType.value]
    // console.log(curData)
    //更新基站数据
    stations.forEach((station,index)=>{
      station.status = curData.bs_status[index]
      station.consumption = curData.bs_consumption[index]
      station.CO2 = curData.bs_CO2[index]
    })
    // console.log(stations)
    //更新用户数据
    users.forEach((user,index)=>{
      //序号减一
      user.res_x_ue = curData.res_x_ue[index] - 1
      user.rate = curData.rate[index][0]
      user.node.children[0].style.fill = colorSelectOptions[user.res_x_ue]
    })
    console.log('碳效',curData.ce,'数据量',curData.data_volume)
      //关闭动画
      loading.close()
      ElMessage('加载完成')
    },2000)
  }else{
    //没有数据报错
    ElMessage('无数据')
  }
}
//选择24小时中的其中一个
const selectTime =(index,ablity) =>{
  if(player.value && !ablity){
    ElMessage('自动播放期间不可主动点击修改')
    return
  }
  curHour.value = index
  //删除连线
  myJsPlumb.deleteEveryConnection();
  //删除以前的节点
  users.forEach((user)=>{
    user.node.remove()
  })
  users.length = 0
  //生成新的用户节点,基站信息不变
  const stationDom = initNode()
  initUsers(stationDom)
}
onBeforeMount(()=>{
  for(let i=0;i<24;i++){
    timeLineContent.push({content:i<10?`0${i}`:`${i}`})
  }
})
onMounted(()=>{
  unitHeight = box.clientHeight/range
  unitWidth = box.clientWidth/range
  box.addEventListener('click',()=>{
    myJsPlumb.deleteEveryConnection()
    refreshOpacity()
  },true)
  const stationDom = initNode()
  initStation(stationDom)
  initUsers(stationDom)
})
onBeforeUnmount(()=>{
  clearInterval(Timer)
  player.value = false
  console.log('clear')
})

</script>
<style scoped>
#mapid { 
	height: 600px; 
}
.container{
  display: flex;
  flex-direction: column;
  justify-content: flex-start; 
  padding: 20px;
  background-color: #f5f5f5; /* 可选背景色 */
  width: 100vw;
  height: 100vh; /* 占满视口高度 */
  position: fixed;
}

.timeLine{
  display: flex;
  flex-direction: row;
  position: relative;
  width:100vw;
}
.player{
  cursor: pointer;
  position: relative;
  left:10px;
}
.timeLineNode{
  width:4%;
  position: relative;
  top:15px;
  left:40px;
  border-top:2px solid #BCD6D2;
}
.dot{
  display: inline-block;
  position: absolute;
  width:10px;
  height:10px;
  border-radius: 50%;
  background-color: #BCD6D2;
  left:0;
  top:0;
  transform: translate(-50%,-50%);
  cursor: pointer;
}
.activeDot{
    width: 16px;
    height: 16px;
    background-color: black;
  }

  .text{
    font-size: 16px;
    font-weight: bold;
    text-align: center;
    transform: translate(-50%,0);
    color: #BCD6D2;
    cursor: pointer;
  }
  .activeText{
    font-size: 20px;
    color: black;
  }

.timeLineNode:last-child{
  border-color: rgba(0,0,0,0);
}

/* 通用白色圆角框样式 */
.box {
  background-color: #fff;
  border-radius: 12px; /* 圆角半径 */
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 添加阴影 */
  width: 100%; /* 左侧框占据整个宽度 */
  height: 100%; /* 占满父容器高度 */
  overflow: auto; /* 当内容超出时启用滚动 */
  overflow: hidden;
  border: 1px solid rgba(0, 0, 0, 0.2);
  position: relative;
}
.map{
    height:300%;
    background: no-repeat center/300% url('../assets/universe.jpeg');
    /* background-position: 0 0; */
}
.floating{
  position: absolute;
  top:100px;
  right:-185px;
  width: 200px;
  background-color: #fff;
  border-radius: 15px;
  padding:10px 10px 10px 0px;
  border: 1px solid rgba(0,0,0,0.4);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 1); /* 添加阴影 */
  z-index:100;
  transition: transform 0.3s ease; /* 添加平滑动画 */
  display: flex;
  flex-direction: row;
}
.floating:hover{
  transform: translateX(-150px);
}
.button {
    padding: 7px 5px;
    font-size: 16px;
    font-weight: bold;
    border-radius: 5px;
    cursor: pointer;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.4);
}
</style>